package com.dragon.common.utils.http;

// import com.dragon.common.utils.spring.SpringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * RestTemplate工具类
 *
 * @author dragon
 * @version 1.0
 * @date 2024/7/17 18:05
 */
public class RestTemplateUtils {

    private static final Logger log = LoggerFactory.getLogger(RestTemplateUtils.class);

    private static RestTemplate restTemplate;


    /**
     * 构建 RestTemplate 实例
     *
     * @return RestTemplate
     */
    public static RestTemplate getInstance() {
        if (Objects.isNull(restTemplate)) {
            // restTemplate = SpringUtils.getBean(RestTemplate.class);
            restTemplate = new RestTemplate();
            // 默认的 RestTemplate 有个机制是请求状态码非200 就抛出异常，会中断接下来的操作
            restTemplate.setErrorHandler(new ResponseErrorHandler() {
                @Override
                public boolean hasError(@NonNull ClientHttpResponse response) throws IOException {
                    return false;
                }

                @Override
                public void handleError(@NonNull ClientHttpResponse response) throws IOException {

                }
            });
        }

        return restTemplate;
    }

    /**
     * 统一执行HTTP请求
     *
     * @param httpMethod   请求方法
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  body请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T toExecute(HttpMethod httpMethod, String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url);

        if (Objects.nonNull(requestParam)) {
            for (Map.Entry<String, Object> entry : requestParam.entrySet()) {
                uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue());
            }
        }

        HttpHeaders httpHeaders = new HttpHeaders();
        if (Objects.nonNull(headers)) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpHeaders.add(entry.getKey(), entry.getValue());
            }
        }

        return getInstance().exchange(uriComponentsBuilder.build().toUri(), httpMethod, new HttpEntity<>(requestBody, httpHeaders), responseType).getBody();
    }


    /*
     * ========================================= GET请求 =========================================
     */

    /**
     * GET请求
     *
     * @param url 请求地址
     * @return 响应结果
     */
    public static String get(String url) {
        return get(url, null, null, String.class);
    }

    /**
     * GET请求
     *
     * @param url          请求地址
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T get(String url, Class<T> responseType) {
        return get(url, null, null, responseType);
    }

    /**
     * GET请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @return 响应结果
     */
    public static String get(String url, Map<String, Object> requestParam) {
        return get(url, requestParam, null, String.class);
    }

    /**
     * GET请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T get(String url, Map<String, Object> requestParam, Class<T> responseType) {
        return get(url, requestParam, null, responseType);
    }

    /**
     * GET请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param headers      请求头
     * @return 响应结果
     */
    public static String get(String url, Map<String, Object> requestParam, Map<String, String> headers) {
        return get(url, requestParam, headers, String.class);
    }

    /**
     * GET请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T get(String url, Map<String, Object> requestParam, Map<String, String> headers, Class<T> responseType) {
        return toExecute(HttpMethod.GET, url, requestParam, null, headers, responseType);
    }


    /*
     * ========================================= POST请求 =========================================
     */

    /**
     * POST请求
     *
     * @param url 请求地址
     * @return 响应结果
     */
    public static String post(String url) {
        return post(url, null, null, null, String.class);
    }

    /**
     * POST请求
     *
     * @param url          请求地址
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T post(String url, Class<T> responseType) {
        return post(url, null, null, null, responseType);
    }

    /**
     * POST请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @return 响应结果
     */
    public static String post(String url, Object requestBody) {
        return post(url, null, requestBody, null, String.class);
    }

    /**
     * POST请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T post(String url, Object requestBody, Class<T> responseType) {
        return post(url, null, requestBody, null, responseType);
    }

    /**
     * POST请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @param headers     请求头
     * @return 响应结果
     */
    public static String post(String url, Object requestBody, Map<String, String> headers) {
        return post(url, null, requestBody, headers, String.class);
    }

    /**
     * POST请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T post(String url, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return post(url, null, requestBody, headers, responseType);
    }

    /**
     * POST请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @return 响应结果
     */
    public static String post(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers) {
        return post(url, requestParam, requestBody, headers, String.class);
    }

    /**
     * POST请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T post(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return toExecute(HttpMethod.POST, url, requestParam, requestBody, headers, responseType);
    }


    /*
     * ========================================= PUT请求 =========================================
     */

    /**
     * PUT请求
     *
     * @param url 请求地址
     * @return 响应结果
     */
    public static String put(String url) {
        return put(url, null, null, null, String.class);
    }

    /**
     * PUT请求
     *
     * @param url          请求地址
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T put(String url, Class<T> responseType) {
        return put(url, null, null, null, responseType);
    }

    /**
     * PUT请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @return 响应结果
     */
    public static String put(String url, Object requestBody) {
        return put(url, null, requestBody, null, String.class);
    }

    /**
     * PUT请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T put(String url, Object requestBody, Class<T> responseType) {
        return put(url, null, requestBody, null, responseType);
    }

    /**
     * PUT请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @param headers     请求头
     * @return 响应结果
     */
    public static String put(String url, Object requestBody, Map<String, String> headers) {
        return put(url, null, requestBody, headers, String.class);
    }

    /**
     * PUT请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T put(String url, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return put(url, null, requestBody, headers, responseType);
    }

    /**
     * PUT请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @return 响应结果
     */
    public static String put(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers) {
        return put(url, requestParam, requestBody, headers, String.class);
    }

    /**
     * PUT请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T put(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return toExecute(HttpMethod.PUT, url, requestParam, requestBody, headers, responseType);
    }


    /*
     * ========================================= PATCH请求 =========================================
     */

    /**
     * PATCH请求
     *
     * @param url 请求地址
     * @return 响应结果
     */
    public static String patch(String url) {
        return patch(url, null, null, null, String.class);
    }

    /**
     * PATCH请求
     *
     * @param url          请求地址
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T patch(String url, Class<T> responseType) {
        return patch(url, null, null, null, responseType);
    }

    /**
     * PATCH请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @return 响应结果
     */
    public static String patch(String url, Object requestBody) {
        return patch(url, null, requestBody, null, String.class);
    }

    /**
     * PATCH请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T patch(String url, Object requestBody, Class<T> responseType) {
        return patch(url, null, requestBody, null, responseType);
    }

    /**
     * PATCH请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @param headers     请求头
     * @return 响应结果
     */
    public static String patch(String url, Object requestBody, Map<String, String> headers) {
        return patch(url, null, requestBody, headers, String.class);
    }

    /**
     * PATCH请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T patch(String url, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return patch(url, null, requestBody, headers, responseType);
    }

    /**
     * PATCH请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @return 响应结果
     */
    public static String patch(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers) {
        return patch(url, requestParam, requestBody, headers, String.class);
    }

    /**
     * PATCH请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T patch(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return toExecute(HttpMethod.PATCH, url, requestParam, requestBody, headers, responseType);
    }


    /*
     * ========================================= DELETE请求 =========================================
     */

    /**
     * DELETE请求
     *
     * @param url 请求地址
     * @return 响应结果
     */
    public static String delete(String url) {
        return delete(url, null, null, null, String.class);
    }

    /**
     * DELETE请求
     *
     * @param url          请求地址
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T delete(String url, Class<T> responseType) {
        return delete(url, null, null, null, responseType);
    }

    /**
     * DELETE请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @return 响应结果
     */
    public static String delete(String url, Object requestBody) {
        return delete(url, null, requestBody, null, String.class);
    }

    /**
     * DELETE请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T delete(String url, Object requestBody, Class<T> responseType) {
        return delete(url, null, requestBody, null, responseType);
    }

    /**
     * DELETE请求
     *
     * @param url         请求地址
     * @param requestBody 请求数据
     * @param headers     请求头
     * @return 响应结果
     */
    public static String delete(String url, Object requestBody, Map<String, String> headers) {
        return delete(url, null, requestBody, headers, String.class);
    }

    /**
     * DELETE请求
     *
     * @param url          请求地址
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T delete(String url, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return delete(url, null, requestBody, headers, responseType);
    }

    /**
     * DELETE请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @return 响应结果
     */
    public static String delete(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers) {
        return delete(url, requestParam, requestBody, headers, String.class);
    }

    /**
     * DELETE请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @param requestBody  请求数据
     * @param headers      请求头
     * @param responseType 响应类型
     * @return 响应结果
     */
    public static <T> T delete(String url, Map<String, Object> requestParam, Object requestBody, Map<String, String> headers, Class<T> responseType) {
        return toExecute(HttpMethod.DELETE, url, requestParam, requestBody, headers, responseType);
    }


    /*
     * ========================================= HEAD请求 =========================================
     */

    /**
     * HEAD请求
     *
     * @param url 请求地址
     * @return 响应头
     */
    public static HttpHeaders head(String url) {
        return getInstance().headForHeaders(URI.create(url));
    }

    /**
     * HEAD请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @return 响应头
     */
    public static HttpHeaders head(String url, Map<String, Object> requestParam) {
        return getInstance().headForHeaders(url, requestParam);
    }

    /*
     * ========================================= OPTIONS请求 =========================================
     */

    /**
     * OPTIONS请求
     *
     * @param url 请求地址
     * @return 响应头
     */
    public static Set<HttpMethod> options(String url) {
        return getInstance().optionsForAllow(URI.create(url));
    }

    /**
     * OPTIONS请求
     *
     * @param url          请求地址
     * @param requestParam URL请求参数
     * @return 响应头
     */
    public static Set<HttpMethod> options(String url, Map<String, Object> requestParam) {
        return getInstance().optionsForAllow(url, requestParam);
    }

}
